/*
 * Copyright (C) 2011, EADS France
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */
package xowl.gmi.view.diagram;

import java.util.ArrayList;
import java.util.List;
import xowl.gmi.view.DragHandler;
import xowl.gmi.view.DropHandler;

/**
 *
 * @author Laurent WOUTERS
 */
public abstract class Widget {
    protected static final Couple MAXSIZE = new Couple(Double.MAX_VALUE, Double.MAX_VALUE);
    
    protected float transparency;
    protected Couple dimension;
    protected Couple position;
    
    public void setTransparency(int value) { this.transparency = value; }
    public Couple getSize() { return dimension; }
    public Couple getPosition() { return position; }
    public void setPosition(Couple point) { position = point; }
    
    public Widget() {
        this.transparency = 1.0f;
    }
    
    public boolean contains(Couple input) {
        if (dimension == null || position == null)
            return false;
        return (input.x >= position.x && input.y >= position.y && input.x <= position.x + dimension.x && input.y <= position.y + dimension.y);
    }
    
    public List<Widget> getStackAt(Couple input) {
        List<Widget> stack = new ArrayList<>();
        buildStackAt(stack, input);
        return stack;
    }
    protected boolean buildStackAt(List<Widget> stack, Couple input) {
        if (!contains(input))
            return false;
        stack.add(this);
        buildStackChildren(stack, input.minus(position));
        return true;
    }
    protected void buildStackChildren(List<Widget> stack, Couple input) { }
    
    public abstract Couple getMinSize();
    public abstract Couple getMaxSize();
    public abstract Couple layout();
    public abstract Couple layout(Couple bounds);
    public abstract void paint(java.awt.Graphics2D g2d, float alpha, DiagramStyle style, Couple offset);
    
    public List<Couple> getVertices() {
        List<Couple> result = new ArrayList<>();
        result.add(new Couple(0, 0));
        result.add(new Couple(0, dimension.y));
        result.add(new Couple(dimension.x, 0));
        result.add(new Couple(dimension.x, dimension.y));
        return result;
    }
    
    public Hull getHull() {
        if (dimension == null)
            layout();
        return new Hull(getVertices());
    }
    
    public boolean isSelectable() { return false; }
    public void toggleSelected() {}
    public boolean isConnectionStart() { return false; }
    public boolean isConnectionEnd() { return false; }
    public void startConnecting() {}
    public void clearConnecting() {}
    public void endConnecting() {}
    
    public boolean onMouseEnter(UserState state, Couple local) { return false; }
    public boolean onMouseLeave() { return false; }
    public boolean onMouseOpenEditor(Diagram diagram) { return false; }
    public boolean onMouseContextMenu(Diagram diagram) { return false; }
    public DragHandler onMouseDrag() { return null; }
    public DropHandler onMouseDrop() { return null; }
    
    protected java.awt.Color getRealColor(java.awt.Color original, float alpha) {
        if (original == null)
            return null;
        int a = (int)(alpha * transparency * original.getAlpha());
        return new java.awt.Color(original.getRed(), original.getGreen(), original.getBlue(), a);
    }
    protected static String getColorString(java.awt.Color color) {
        String red = Integer.toHexString(color.getRed());
        String green = Integer.toHexString(color.getGreen());
        String blue = Integer.toHexString(color.getBlue());
        if (red.length() == 1) red = "0" + red;
        if (green.length() == 1) green = "0" + green;
        if (blue.length() == 1) blue = "0" + blue;
        return red + green + blue;
    }
    protected static java.awt.FontMetrics getFontMetrics(java.awt.Font font) {
        return sun.font.FontDesignMetrics.getMetrics(font);
    }
    
    public java.awt.Image getStaticImage() {
        DiagramStyle style = new DiagramStyle();
        return exportBMP(style);
    }
    
    public java.awt.image.BufferedImage exportBMP(DiagramStyle style) {
        java.awt.image.BufferedImage image = new java.awt.image.BufferedImage((int)dimension.x + 2, (int)dimension.y + 2, java.awt.image.BufferedImage.TYPE_3BYTE_BGR );
        java.awt.Graphics2D g2d = image.createGraphics();
        g2d.setRenderingHint(java.awt.RenderingHints.KEY_ANTIALIASING, java.awt.RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(java.awt.RenderingHints.KEY_TEXT_ANTIALIASING, java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g2d.setBackground(style.diagramBackground);
        g2d.clearRect(0, 0, (int)dimension.x + 2, (int)dimension.y + 2);
        paint(g2d, 1, style, position.inverse().plus(1));
        g2d.dispose();
        return image;
    }
    
    public org.w3c.dom.Document exportSVG(DiagramStyle style) {
        org.w3c.dom.Document doc = new org.apache.xerces.dom.DocumentImpl();
        org.w3c.dom.Element root = doc.createElementNS("http://www.w3.org/2000/svg", "svg");
        root.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
        root.setAttribute("version", "1.1");
        root.setAttribute("width", Integer.toString((int)dimension.x + 2) + "px");
        root.setAttribute("height", Integer.toString((int)dimension.y + 2) + "px");
        root.setAttribute("viewBow", "0 0 " + Integer.toString((int)dimension.x + 2) + " " + Integer.toString((int)dimension.y + 2));
        doc.appendChild(root);
        exportSVG(doc, root, 1.0f, style, new Couple(0,0));
        return doc;
    }
    protected abstract void exportSVG(org.w3c.dom.Document doc, org.w3c.dom.Element parent, float alpha, DiagramStyle style, Couple offset);
}
